// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package cgo

import (
	"sync"
	"sync/atomic"
)

// Handle提供了一种方法，可以在Go和C之间传递包含Go指针的值
// （指向Go分配的内存的指针），而无需违反cgo指针传递规则。句柄是一个整数
// 值，可以表示任何Go值。一个句柄可以通过C传递给
// 并返回Go，Go代码可以使用该句柄来检索原始Go值。
// 
// 句柄的基础类型保证适合整数类型
// 该类型足够大，可以容纳任何指针的位模式。句柄的零
// 值无效，因此在C API中用作哨兵
// 是安全的。例如，在移动端：
// 
// package main 
// 
// *
// 对于uintptr_t 
// 
// 外部无效MyGoPrint（uintptr_t句柄）；
// void myprint（uintptr__t handle）；
// */
// 导入“C”
// 导入“runtime/cgo”
// /
// 函数MyGoPrint（句柄C.UINTPG
// val:=h.Value（）（字符串）
// func main（）{
// val:=“hello Go”
// C.myprint（C.uintpttr_t（cgo.NewHandle（val）））
// /输出：hello Go 
// }
// 
// /在C端：
// 
// 
// /一个Go函数
// /外部无效MyGoPrint（uintptr_t句柄）；
// 
// A C函数
// void myprint（uintptr_t handle）{
// MyGoPrint（handle）；
// }
// 
// 某些C函数接受指向调用方提供的任意
// 数据值的void*参数。强制cgo是不安全的。处理
// （一个整数）到一个不安全的状态。指针，但我们可以传递cgo的地址
// 。void*参数的句柄，如
// 前面的示例：
// 
// package main 
// 
// *
// 外部void MyGoPrint（void*上下文）；
// /静态内联void myprint（void*context）{
// MyGoPrint（context）；
// }
// */
// /导入“C”
// /导入（
// ”runtime/cgo“
// /h:=*（*cgo.Handle）（context）
// /val:=h.Value（）（string）
// /输出：hello Go 
// }
type Handle uintptr

// /NewHandle返回给定值的句柄。
// 
// 句柄在程序对其调用Delete之前有效。句柄
// 使用资源，此包假设C代码可能会保留句柄
// 因此当不再需要句柄
// 时，程序必须显式调用Delete。
// 
// 预期用途是将返回的句柄传递给C代码，C代码
// 将其传递回Go，后者调用Value。
func NewHandle(v any) Handle {
	h := atomic.AddUintptr(&handleIdx, 1)
	if h == 0 {
		panic("runtime/cgo: ran out of handle space")
	}

	handles.Store(h, v)
	return Handle(h)
}

// Value返回有效句柄的相关Go值。
// 
// 如果句柄无效，该方法将崩溃。
func (h Handle) Value() any {
	v, ok := handles.Load(uintptr(h))
	if !ok {
		panic("runtime/cgo: misuse of an invalid Handle")
	}
	return v
}

// 删除使句柄无效。此方法只应调用一次
// 程序不再需要将句柄传递给C，C代码
// 不再具有句柄值的副本。
// 
// 如果句柄无效，则该方法会崩溃。
func (h Handle) Delete() {
	_, ok := handles.LoadAndDelete(uintptr(h))
	if !ok {
		panic("runtime/cgo: misuse of an invalid Handle")
	}
}

var (
	handles   = sync.Map{} // 映射[Handle]接口{}
	handleIdx uintptr      // 原子
)
